# -*- coding: utf-8 -*-
"""
Created on Wed Feb  7 15:12:10 2018

@author: wangliangju@gmail.com

"""
from smalltools import Files, Table, Tools
from utilsImage import Processing
import numpy as np
import matplotlib.pyplot as plt
import cv2
import spectral as speclib
import os
import time
import math
from utilsImage import Contours
import json

class HyperImage:
    
    """ """

    def __init__(self, hyperimg, wvlist, isDebug=False):
        self.hyperImg = hyperimg
        self.wvs = wvlist
        self.HEIGHT, self.WIDTH, self.BANDS = hyperimg.shape
        self.SHAPE = hyperimg.shape
        self.wvdict = dict(zip(wvlist, range(0, self.BANDS)))
        self.isDebug = isDebug
    
    @classmethod    
    def readENVIdata(cls, path):
        """Read hyperspectral image from envi head file path then creat an
        object
        
        Args:
            path: the path of envi head file
        Returns:
            creat an object
            
        """
        
        imgh = speclib.open_image(path)
        arr = imgh.load()
        wv = imgh.bands.centers
        return cls(arr, wv)

    def _getWvFromIndex(self, i):
        """Get wavelength from the pixel index of the spectrum image

        Args:
          i: The pixel index of the image in column direction
        Returns:
          The wavelength

        """
        
        return list(self.wvdict.keys())[list(self.wvdict.values).index(i)] 

    def _getIndexFromWv(self, wv):
        """Get the pixel index in colomn direction from the wavelength

        Args:
          wv: The wavelength
        Returns:
          The pixel index

        """
        
        _, wvPurp = min(enumerate(self.wvdict.keys()),                          # enumerate:返回索引、值
                        key=lambda x: abs(x[1]-wv))                             # min(x,key=lambda:_):_对x处理，返回x的最小值
        return self.wvdict[wvPurp]

    @classmethod
    def caliColor(cls, src, whiteRefSrc, wv, refceStedBoard,
                      imgingtype = 1, bits=16):
        '''
        0:输入图像数据、标准板数据、标准板反射率
        1:输入图像数据、白板数据、黑板

        Parameters
        ----------
        cls : TYPE
            DESCRIPTION.
        src : TYPE
            DESCRIPTION.
        whiteRefSrc : TYPE
            DESCRIPTION.
        refceStedBoard : TYPE
            DESCRIPTION.
        wv : TYPE
            DESCRIPTION.
        ax : TYPE, optional
            DESCRIPTION. The default is 0.
        imgingtype : bool
            0 - Grey standard board; 1 - White Teflon Board
        bits : TYPE, optional
            DESCRIPTION. The default is 16.

        Returns
        -------
        TYPE
            The spectrum calibrated image.

        '''
        if imgingtype == 0:
            refcestedSrc = np.loadtxt(refceStedBoard, dtype=np.float32)
            refcestedSrc = np.repeat(refcestedSrc[np.newaxis,:], 
                                           whiteRefSrc.shape[0], axis=0)
            refcestedSrc = np.repeat(refcestedSrc[:,np.newaxis,:], 
                                           whiteRefSrc.shape[1], axis=1)
            # print('whiteRefSrc shape>>', whiteRefSrc.shape)
            illumination = Tools.div(whiteRefSrc, refcestedSrc)
            whiteRef = np.mean(illumination, axis=(0,1))
            white = np.repeat(whiteRef[np.newaxis,:], src.shape[0], axis=0)
            white = np.repeat(white[:,np.newaxis,:], src.shape[1], axis=1)
            # print('whiteRef shape>>', white.shape)
            retV = Tools.div(src, white)
        elif imgingtype == 1:
            whiteRef = np.mean(whiteRefSrc, axis=(0,1))
            white = np.repeat(whiteRef[np.newaxis,:], src.shape[0], axis=0)
            white = np.repeat(white[:,np.newaxis,:], src.shape[1], axis=1)
            # print('whiteRefSrc shape>>', white.shape)
            retV = Tools.div((src-refceStedBoard), (white-refceStedBoard))
            # retV = Tools.div(src, white)
        return cls(retV, wv) 

    @classmethod
    def crop1(cls, img, crpPst, wvlist, isDebug=False, path = None):
        '''
        白板裁剪

        Parameters
        ----------
        cls : TYPE
            DESCRIPTION.
        img : TYPE
            DESCRIPTION.
        crpPst : list
            [a,b,c,d] → img[a:a+c, b:b+d, :]
        wvlist : TYPE
            DESCRIPTION.
        isDebug : TYPE, optional
            DESCRIPTION. The default is False.
        path : TYPE, optional
            DESCRIPTION. The default is None.

        Returns
        -------
        TYPE
            DESCRIPTION.

        '''
        crpPst = [int(c) for c in crpPst]
        dst = img[crpPst[1]:crpPst[1]+crpPst[3],
                  crpPst[0]:crpPst[0]+crpPst[2],:]
        demo_0 = img[:,:,50]
        demo_0 = np.squeeze(demo_0)
        demo_1 = dst[:,:,50]
        demo_1 = np.squeeze(demo_1)
        if isDebug == True:
            plt.imshow(demo_0)
            plt.show()
            plt.close()
            plt.imshow(demo_1)
            plt.show()
            plt.close()
        if path is not None:
            plt.imshow(demo_1)
            plt.savefig(path)
            plt.close()
        return cls(dst,wvlist)   

    def crop2(self, th = 0, denoisSize = 0, denoiseIter = 1,
                contourThresh = [0,0], path = None):
        redwv = 680
        nirwv = 750
        h,w,b = self.hyperImg.shape
        rindex = HyperImage.getIndexFromList(self.wvs, redwv)
        nirindex = HyperImage.getIndexFromList(self.wvs, nirwv)
        edgelength = nirindex - rindex                                          
        weight = np.arange(-edgelength/2.0+0.5, edgelength/2.0+0.5)
        img2d = self.hyperImg[:,:,rindex:nirindex].reshape((-1,edgelength))
        img1d = np.matmul(img2d, weight)/np.matmul(weight.T, weight)**0.5
        img2seg = img1d.reshape((h,w))
        mask = img2seg.copy()                                                   

        makedImg, mask = self.segmentation_re(th, mask=mask,
                    denoisSize=denoisSize,
                    denoiseIter=denoiseIter,
                    contourThresh=contourThresh,path=path)
        return makedImg, mask

    @classmethod
    def swapaxes(cls, src, wv, axes1,axes2):
        retV = np.swapaxes(src, axes1,axes2)                                    # numpy.swapaxes(arr, axis1, axis2)
        return cls(retV, wv)                                                    # 接受一对轴编号，进行轴对换

    @staticmethod
    def caliColor2(src, whiteRef, axis = 0, imgingtype=1, bits=16):             # 不用 #
        """Calibrate the image spectrum by dividing the white reference
        Args:
          imgingtype:  (Default value = 0). 0 - the camera and the light 
          are fixed, only the image on a line is required for white reference; 
          1 - the camera and the light are not relatively fixed, the full 
          dimension white reference image is required.
        Returns:
          The spectrum calibrated image
          
        """

        retV = np.zeros(src.shape, dtype=np.float)
        if imgingtype == 0:
            if axis==0:
                white = np.repeat(whiteRef[np.newaxis, :, :], src.shape[axis],
                                  axis=axis)
            elif axis == 1:
                white = np.repeat(whiteRef[:, np.newaxis, :], src.shape[axis], 
                                  axis=axis)
            retV = Tools.div(src, white)
        elif imgingtype == 1:
            retV = Tools.div(src, whiteRef) 
        #retV = np.uint16(retV*(2**bits-1))
        return retV

    def display1Band(self, imgsrc=None, wv = 400, isshow=False, path = None):
        """Get and Display the heatmap

        Args:
          imgsrc:  (Default value = None). With the default value, 
                  the function will use 400 as the src image.
          isshow:  (Default value = False). With the default value, 
                  the function won't show the heatmap.
        Returns:
          The heatmap numpy array

        """

        if imgsrc is None:
            imgsrc = self.getBand(wv)
        cmap = plt.get_cmap('jet')
        heatmap = np.delete(cmap(imgsrc), 3, 2)*255                             # jet:蓝-青-黄-红，delete去除蓝色
        if isshow is True:      
            #cv2.imshow('heatmap', imgsrc)
            #cv2.waitKey(0)   # 无限等待
            plt.imshow(imgsrc, cmap=cmap)
            plt.show()
        if path is not None:
            cv2.imwrite(path, heatmap)
            # plt.imshow(imgsrc, cmap=cmap)
            # plt.savefig(path)
            # plt.close()
        #return heatmap
        
    @staticmethod
    def display1DArray(ar, x, isshow=True, path=None):
        """Get and display 1d array

        Args:
          ar: The value list to show
          x: The x list to show
          arrtype: array type. 0, the mean spectrum....
          isshow:  (Default value = False). 
                  With the default value, the image won't be shown.
        Returns:
            The plot image numpy array

        """

        fig = plt.figure()
        plot = fig.add_subplot(111)
        plot.plot(x, ar)
        data = Tools.fig2data(fig)                                             #将 Matplotlib 图形转换为具有 RGBA 通道的三维 numpy 数组并返回
        plt.close()
        if isshow is True:
            cv2.imshow('spectrum', data)
            cv2.waitKey(0)
        if path is not None:
            cv2.imwrite(path, data)
        return data

    def getLeafPara(self, spec, path = ''):                                     # 根据公式修改，待确定 #
        """Get parameters of leaf with the mean of all spectrums on the leaf

        Args:
            spec: The spectrum list
        Returns:
            The value number of NDVI, NRI, CI, SPAD.

        """
        wvls = self.wvs
        # get the spec index.
        # ndvi = (800b - 650b) / (800b + 650b)
        index800b, _ = min(enumerate(wvls),
                           key=lambda x: abs(x[1] - 850))
        index700b, _ = min(enumerate(wvls),
                           key=lambda x: abs(x[1] - 650))
        self.paraNDVI = float(abs(spec[index800b] - spec[index700b])) / (
            spec[index800b] + spec[index700b])
        if math.isnan(self.paraNDVI):                                           # isnan:非数字返回true
            self.paraNDVI = 0
        # nri = (570b - 670b) / (570b + 670b)
        index570b, _ = min(enumerate(wvls),
                           key=lambda x: abs(x[1] - 570))
        index670b, _ = min(enumerate(wvls),
                           key=lambda x: abs(x[1] - 670))
        self.paraNRI = float(abs(spec[index570b] - spec[index670b])) / (
            spec[index570b] + spec[index670b])
        if math.isnan(self.paraNRI):
            self.paraNRI = 0

        # ci = (750b - 705b) / (750b + 705b)
        index750b, _ = min(enumerate(wvls),
                           key=lambda x: abs(x[1] - 750))
        index705b, _ = min(enumerate(wvls),
                           key=lambda x: abs(x[1] - 705))
        self.paraCI = float(abs(spec[index750b] - spec[index705b])) / (
            spec[index750b] + spec[index705b])
        if math.isnan(self.paraCI):
            self.paraCI = 0

        # spad = 800b/650b
        index800b, _ = min(enumerate(wvls),
                           key=lambda x: abs(x[1] - 800))
        index650b, _ = min(enumerate(wvls),
                           key=lambda x: abs(x[1] - 650))
        self.paraSpad = float(spec[index800b] / spec[index650b])/10.0
        if math.isnan(self.paraSpad):
            self.paraSpad = 0
        # fluorescence = 735b / 700b
        index735b, _ = min(enumerate(wvls),
                           key=lambda x: abs(x[1] - 735))
        index700b, _ = min(enumerate(wvls),
                           key=lambda x: abs(x[1] - 700))
        self.paraFluo = float(spec[index735b] / spec[index700b])/10.0
        if math.isnan(self.paraFluo):
            self.paraFluo = 0
        para = {'NDVI':self.paraNDVI, 'NRI':self.paraNRI, 
                'CI':self.paraCI, 'Spad':self.paraSpad}
        if path != '':
            with open(path, 'w') as f:
                [f.write('{0},{1}\n'.format(key, value)) 
                 for key, value in para.items()]
        return para
    
    def getLeafParaSeg(self, spec_list, path=''): 
        seg_list = []
        for i in range(len(spec_list)):
            spec = spec_list[i][0]
            seg = self.getLeafPara(spec)
            seg_list.append(seg)
            if path != '':
                with open(path + '/parameters_seg' + str(i) + '.csv',
                          'w') as f:
                    [f.write('{0},{1}\n'.format(key, value)) 
                     for key, value in seg.items()]
        return seg_list
    
    def getMean(self, img, axis=0, meantype=0, path=''):
        """Get the mean of hyperImg

        Args:
          axis:  (Default value = 0). 0 mean the height, 1 mean the width, 
                  2 mean the depth (0,1) mean the height and width.
          meantype:  (Default value = 1). 0 mean the nonzero value,
                  1 normal mean.
        Returns:
            retV: The mean result data

        """

        if meantype == 1:
            retv = np.mean(img, axis=axis)
        elif meantype == 0:
            zeropsth, zeropstw = np.where(~img.any(axis=2))                     # 获取反射值为0区域的坐标
            img[zeropsth, zeropstw, :] = np.nan                                 # 对反射值为0的坐标区赋值，not a number
            retv = np.nanmean(img, axis=axis)                                   # nanmean() 在计算算术平均数时如果遇到 NaN 值会忽略
        if path != '':
            np.savetxt( path, retv, delimiter=',' )
        return retv

    def getSpectrum(self):
        """Get the mean of hyperImg

        Returns:
            retV: The mean result data

        """
        prc = Processing()
        retv = prc.averageImgWithMask(self.hyperImg)[0]
  
        return retv
    
    def getNDVIImg(self, img=None, redIndex=660, infraredIndex=850,
                bandWidth=5):
        """Get the ndvi image

        Args:
          img:  (Default value = None)
        Returns:
            NDVI float type image

        """

        if img is None:
            img = self.hyperImg
        imgInf = self.getBand(infraredIndex, bandWidth=bandWidth)
        imgRed = self.getBand(redIndex, bandWidth=bandWidth)
        #print(img680.shape)
        ndviImg = Tools.div((imgInf-imgRed), (imgInf+imgRed))
        # self.ndviImg = ndviImg
        return ndviImg
    
    def getMask2DArray(self, axisremove=2):                                     # mask 三维转二维的高光谱数据（可能用不到）#
        if axisremove == 2:
            arr2d = self.hyperImg.reshape((-1,self.BANDS))
            mask1d = self.mask.reshape((-1))
        rst2d = arr2d[mask1d>0.5, :]
        return rst2d
    
    def binningSpecsList(self, speclist,bsize):                                 # 把bsize个波段合并成一个波段，返回speclist的平均反射值（可能用不到）#
        specs = speclist[0:int(speclist.shape[0]/bsize)*bsize, :]               # int()：向下取整   #speclist：[波长，平均反射值]   
        specs2 = specs.reshape((-1,bsize,2))
        specs3 = specs2.mean(axis=1)
        return specs3

    def binningSpatial(self):
        pass
        
    def segmentation(self, th, mask=None, denoisSize = 0, denoiseIter = 1,
                    contourThresh=[0,0], path=None):
        """Segment the hyperImg with NDVI image if ndvi is none

        Args:
          img:  (Default value = None). The segmentation image
          th: Threshold
        Returns:
            makedImg: the segmented hyperspectral image
            mask: the mask image used for the segmentation

        """
        prc = Processing()
        mask = prc.segment(mask, th)
        if self.isDebug == True:
            plt.imshow(mask)
            plt.title('Raw mask')
            plt.show()

        if denoisSize > 0:
            mask = prc.imgFilter(mask, kernelSize=denoisSize,
                                times=denoiseIter)
            if self.isDebug == True:
                plt.imshow(mask)
                plt.title('mask after imgFilter')
                plt.show()
        if contourThresh != [0,0]:                                              # 面积降噪（一般在这不用）
            mask = prc.contoursFilter(mask, thresh=contourThresh, color=1)
            if self.isDebug == True:
                plt.imshow(mask)
                plt.title('mask after contoursFilter')
                plt.show()
        makedImg = prc.maskImage(self.hyperImg, mask)
        if path is not None:
            plt.imshow(mask)
            plt.savefig(path,dpi = 300)
            plt.close()
        self.makedImg = makedImg
        self.mask = mask
        return makedImg, mask
    
    def segmentation_re(self, th, mask=None, denoisSize = 0, denoiseIter = 1,
                        contourThresh=[0,0], path=None):
        """Segment the hyperImg with NDVI image if ndvi is none(mask值反向)

        Args:
          img:  (Default value = None). The segmentation image
          th: Threshold
        Returns:
            makedImg: the segmented hyperspectral image
            mask: the mask image used for the segmentation

        """
        prc = Processing()
        mask = prc.segment_re(mask, th)
        if self.isDebug == True:
            plt.imshow(mask)
            plt.title('Raw mask')
            plt.show()

        if denoisSize > 0:
            mask = prc.imgFilter(mask, kernelSize=denoisSize,
                                times=denoiseIter)
            if self.isDebug == True:
                plt.imshow(mask)
                plt.title('mask after imgFilter')
                plt.show()
        if contourThresh != [0,0]:                                              # 面积降噪（一般在这不用）
            mask = prc.contoursFilter(mask, thresh=contourThresh, color=1)
            if self.isDebug == True:
                plt.imshow(mask)
                plt.title('mask after contoursFilter')
                plt.show()
        makedImg = prc.maskImage(self.hyperImg, mask)
        if path is not None:
            plt.imshow(mask)
            plt.savefig(path, dpi = 300)
            plt.close()
        self.makedImg = makedImg
        self.mask = mask
        return makedImg, mask
    
    def segNDVI(self, th = 0, denoisSize = 0, denoiseIter = 1,
                contourThresh = [0,0], path = None):
        ndvi_img = self.getNDVIImg()
        makedImg, mask = self.segmentation(th, mask=ndvi_img, 
                                           denoisSize=denoisSize, 
                                           denoiseIter = denoiseIter, 
                                           contourThresh=contourThresh, 
                                           path = path)
        self.ndvi = ndvi_img
        return makedImg, mask
        
    def segRedEdge(self, th = 0, denoisSize = 0, denoiseIter = 1,
                contourThresh = [0,0], path = None):
        redwv = 680
        nirwv = 750
        h,w,b = self.hyperImg.shape
        rindex = HyperImage.getIndexFromList(self.wvs, redwv)
        nirindex = HyperImage.getIndexFromList(self.wvs, nirwv)
        edgelength = nirindex - rindex                                          # 边界长度（波段数）
        weight = np.arange(-edgelength/2.0+0.5, edgelength/2.0+0.5)             # 定义卷积核，一维向量（edgelength）
        img2d = self.hyperImg[:,:,rindex:nirindex].reshape((-1,edgelength))     # 选择红外波段，生成二维图像（h*w，edgelength）
        img1d = np.matmul(img2d, weight)/np.matmul(weight.T, weight)**0.5       # 处理图像，放大叶片反射率的上升幅度，减小杂物反射率，生成一维数据（h*w，1）
        img2seg = img1d.reshape((h,w))                                          # 重建图像，二维图像（h，w），叶片部分为高值
        mask = img2seg.copy()                                                   

        makedImg, mask = self.segmentation(th, mask=mask,
                    denoisSize=denoisSize,
                    denoiseIter=denoiseIter,
                    contourThresh=contourThresh,path=path)
        return makedImg, mask
    
    def getIndexFromList(wvlist, wv):
        """Get the pixel index in colomn direction from the wavelength
    
        Args:
          wv: The wavelength
        Returns:
          The pixel index
    
        """
        bands = len(wvlist)
        wvdict = dict(zip(wvlist, range(0, bands)))
        _, wvPurp = min(enumerate(wvdict.keys()),
                        key=lambda x: abs(x[1]-wv))
        return wvdict[wvPurp]
    
    def getBand(self, wv, bandWidth=0):
        '''
        获取二维光谱图像数据（全光谱平均数据、wv波长数据、bandwidth宽度的平均数据）

        Parameters
        ----------
        wv : TYPE
            DESCRIPTION.
        bandWidth : TYPE, optional
            DESCRIPTION. The default is 0.

        Returns
        -------
        rtv : TYPE
            DESCRIPTION.

        '''
        if wv == -1:
            rtv = np.mean(self.hyperImg, axis=2)
        else:
            if bandWidth==0:
                rtv = self.hyperImg[:, :, self._getIndexFromWv(wv)]
                rtv = np.squeeze(rtv)                                           # 三维转二维
            else:
                halfReg = int(bandWidth/2)
                img = self.hyperImg[:, :,
                                    self._getIndexFromWv(wv-halfReg):
                                        self._getIndexFromWv(wv+halfReg)]
                rtv = np.mean(img, axis=2)
            #print(wv, 'nm index is:', self._getIndexFromWv(wv))
        return rtv
    
    def getRGB(self, weight=1, isshow=False, path = None, multi=1):

        rind = self._getIndexFromWv(680)
        r = np.mean(self.hyperImg[:, :, rind-5:rind+5], axis=2)
        gind = self._getIndexFromWv(550)
        g = np.mean(self.hyperImg[:, :, gind-5:gind+5], axis=2)
        bind = self._getIndexFromWv(470)
        b = np.mean(self.hyperImg[:, :, bind-5:bind+5], axis=2)

        # r = self.getBand(680)
        # g = self.getBand(550)
        # b = self.getBand(470)
        rgb=cv2.merge([b,g,r])
        # bgr = np.zeros((self.HEIGHT, self.WIDTH, 3), dtype=np.uint16)           # matlab 的排列顺序是R,G,B    # opencv中，排列顺序是B,G,R
        # bgr[:,:,0] = np.uint16(b*weight*65535)                                  # weight可防止标定超过1     # 双字节无符号整数的最大值65535
        # bgr[:,:,1] = np.uint16(g*weight*65535)
        # bgr[:,:,2] = np.uint16(r*weight*65535)
        # bgr = bgr*multi
        if isshow is True:
            #plt.imshow(rgb)
            cv2.imshow('rgb',rgb)
            cv2.waitKey(0)
        if path is not None:
            #plt.savefig(path)
            #plt.show()
            cv2.imwrite(path, rgb)
        return rgb

    def getRGBWithSensitivity(self, sensitivity, weight=1):                     # 高光谱照片模拟相机*传感器的敏感度（一般不会用到）
 
        bgr = np.matmul(self.hyperImg, sensitivity)
        bgr = np.uint16(bgr*weight*65535)
        return bgr

    def updateWhiteRef(self, refimg):
        """Update the white reference

        Args:
          refimg: the white reference image with single channel.
        Returns:
            None

        """

        self.imgWhiteRef = refimg

    @staticmethod
    def singleChannelInterpolation(src, pst):                                   # 单通道的图像插值（一般用不到）
        """Single channel image interpolation with position list 
            which is coupling with column index.

        Args:
          imgsr: The image to interpolate.
          pstlist: The position list of the column index.
        Returns:
            data: The interpolated image.

        """

        pstMax = pst.max()
        pstMin = pst.min()
        pstDst = np.uint16(np.arange(0, pstMax-pstMin, 1))
        pst = pst - pstMin
        a, = pstDst.shape
        #print(a)
        listPstDst = []
        i=0
        for p in pst:
            j = i
            while i < a:
                pd = pstDst[i]
                if p > pd:
                    #print ('aa', p, pd)
                    i += 1
                else: 
                    listPstDst.append(pstDst[j:i])
                    break
        
        listPstDst = listPstDst[1:]
        srcLeft = src[:,0:-1]
        srcRight = src[:,1:]
        pstLeft = pst[0:-1]
        pstRight = pst[1:]
        srcDelta = np.float32(srcRight) - srcLeft
        pstDelta = pstRight - pstLeft
        i = 0
        k = 0
        dst = np.zeros([src.shape[0], a], src.dtype)
        for ar in listPstDst:
            paraK = np.float32(srcDelta[:,i] / pstDelta[i])
            pl = pstLeft[i]
            srcl = srcLeft[:,i]
            for j in ar:
                dst[:,k] = srcl + paraK*(j - pl)
                k += 1
            i += 1
        return dst

    @staticmethod
    def hyperSpecImgInterpolation(src, pst):                                    # 列索引高光谱图像插值（一般用不到）
        """Hyperspectral image interpolation on the column according the 
            position of each column index.

        Args:
          imgsrc: The hyperspectral image to be interpolated.
          pstlist: The position list of the column index
        Returns:
            data: the interpolated hyperspectral image.

        """

        pstMax = pst.max()
        pstMin = pst.min()
        pstDst = np.uint16(np.arange(0, pstMax-pstMin, 1))
        pst = pst - pstMin
        a, = pstDst.shape
        #print(a)
        listPstDst = []
        i=0
        for p in pst:
            j = i
            while i < a:
                pd = pstDst[i]
                if p > pd:
                    #print ('aa', p, pd)
                    i += 1
                else: 
                    listPstDst.append(pstDst[j:i])
                    break
        
        listPstDst = listPstDst[1:]
        srcLeft = src[:,0:-1,:]
        srcRight = src[:,1:,:]
        pstLeft = pst[0:-1]
        pstRight = pst[1:]
        srcDelta = np.int32(srcRight) - srcLeft
        pstDelta = pstRight - pstLeft
        i = 0
        k = 0
        dst = np.zeros([src.shape[0], a, src.shape[2]], dtype=np.uint16)
        for ar in listPstDst:
            paraK = np.float32(srcDelta[:,i,:] / pstDelta[i])
            pl = pstLeft[i]
            srcl = srcLeft[:,i,:]
            for j in ar:
                dst[:,k,:] = srcl + paraK*(j - pl)
                k += 1
            i += 1
        return dst
        
    def leavesSegmentation(self, imgsrc, mask, threshold = 0, path=''):
        """ Segment leaves and Get the average reflectance 
        value of each channel 
        
        """
        contours = Contours.getContours(mask)
        thresholdcnts = Contours.thresholdContours(contours, threshold)
        sortcnts = Contours.sort(thresholdcnts, method='leftRight')
        averageValues = []
        for i in range(0,len(sortcnts)):
            sortcnt_list = []
            img0 = np.zeros((self.HEIGHT,self.WIDTH), dtype=np.uint8)
            sortcnt=sortcnts[i]
            sortcnt_list.append(sortcnt)
            img0cnt=Contours.fillContours(img0, sortcnt_list, color=1)
            prc=Processing()
            average = prc.averageImgWithMask(imgsrc, mask=img0cnt)
            if path is not None:
                plt.imshow(img0cnt)
                plt.savefig(path + '/segment_' + str(i+1) + '.png')
                plt.close()
                np.savetxt(path + '/spectrum_seg' + str(i+1) + '.csv', 
                           average[0], delimiter=',' )
            averageValues.append(average)
        return averageValues, len(sortcnts)

    @staticmethod
    def saveData2Json(data, path=None):
        try:
            with open(path, 'w') as fr:
                json.dump(data, fr, indent=1)
        except TypeError:
            try:
                for i in range(len(data)):
                    data[i][0]=data[i][0].tolist()
                with open(path, 'w') as fr:
                    json.dump(data, fr, indent=1)
            except IndexError:
                data = data.tolist()
                with open(path, 'w') as fr:
                    json.dump(data, fr, indent=1)
                
                
    @staticmethod
    def readJson2Data(path=None):
        with open(path,'r') as fr:
            data = json.load(fr)
        for i in range(len(data)):
            data[i]=np.array(data[i]) 
        return data


def mkDir(path=None):
	folder = os.path.exists(path)
	if not folder:
		os.makedirs(path)


def saveHSI(fpath, data, wv=[], meta=None):
    """save hyperspectral image as .raw and .hdr
    
    Arguments:
        fpath {[str]} -- [the path of the hdr file]
        data {[numpy.array]} -- [data in 3d and 16bit]
    
    Keyword Arguments:
        meta {[dict]} -- [hdr information] (default: {None})
            md = {'scan time': '01/18/2017 14:27:23 PM',
                'camera model': 'flyusb3',
                'data type': 12,
                'header offset': 0,
                'interleave': 'bil',
                'byte order': 0,

                'ext': 'raw',
                'wavelength units': 'nm',
                'position units': 'mm',

                'lines': H,  # [necessay] how many lines
                'samples': W, # [necessay] how many pixels of each line
                'bands': B, # [necessay] how many bands

                'framerate': 30.000, # frame rate
                'roi left' : 0,
                'roi width': 0,
                'roi top' : 0,
                'roi height': 0,

                'wavelength': wv, # [necessay] wavelength list
                'line position': lpst # list of positions of lines
                }
    
    Returns:
        [dict] -- [metadata with all information]
    """
    printHeader = 'hyperimage.saveHImage >>> '
    H,W,B = data.shape
    if type(wv) == list:
        if wv == []:
            wv = np.linspace(400,1100, num=B) # wavelength
        else:
            wv = np.asarray(wv)
            
    
    lpst = np.linspace(0,1000, num=W) # lines' position
    
    md = {'scan time': '01/18/2017 14:27:23 PM',
        'save time': time.ctime(),
        'camera model': 'flyusb3',
        'data type': 12,
        'header offset': 0,
        'interleave': 'bil',
        'byte order': 0,

        'ext': 'raw',
        'wavelength units': 'nm',
        'position units': 'mm',

        'lines': H,  # [necessay] how many lines
        'samples': W, # [necessay] how many pixels of each line
        'bands': B, # [necessay] how many bands

        'framerate': 30.000, # frame rate
        'roi left' : 0,
        'roi width': 0,
        'roi top' : 0,
        'roi height': 0,

        'wavelength': wv, # [necessay] wavelength list
        'line position': lpst # list of positions of lines
        }
        
    if meta != None:
        for k, v in meta.items():
            md[k] = v
    try:
        img = speclib.envi.create_image(fpath, metadata=md, ext='.raw', force=False)            #write
    except speclib.io.envi.EnviException as inst:
        print(printHeader, type(inst), sep='')    # the exception instance
        print(printHeader, inst.args, sep='')
        path, nameonly, exthdr = Files.splitPath(fpath)
        fpathNew = os.path.join(path, nameonly+'_new' + str(int(time.time())) + '.' +exthdr) 
        print(printHeader, 'The data was saved in: ', fpathNew, sep='')
        img = speclib.envi.create_image(fpathNew, metadata=md, ext='.raw', force=False)

    mm = img.open_memmap(writable=True)     #read
    mm[:,:,:] = data
    return md



        